package com.zbkj.crmeb.payment.wechat.impl;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import com.utils.*;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.constants.Constants;
import com.constants.WeChatConstants;
import com.crmeb.core.exception.CrmebException;
import com.zbkj.crmeb.payment.vo.wechat.CreateOrderH5SceneInfoDetailVo;
import com.zbkj.crmeb.payment.vo.wechat.CreateOrderH5SceneInfoVo;
import com.zbkj.crmeb.payment.vo.wechat.CreateOrderRequestVo;
import com.zbkj.crmeb.payment.vo.wechat.CreateOrderResponseVo;
import com.zbkj.crmeb.payment.vo.wechat.PayParamsVo;
import com.zbkj.crmeb.payment.wechat.WeChatPayService;
import com.zbkj.crmeb.store.model.StoreOrder;
import com.zbkj.crmeb.store.service.StoreOrderInfoService;
import com.zbkj.crmeb.store.service.StoreOrderService;
import com.zbkj.crmeb.system.service.SystemConfigService;
import com.zbkj.crmeb.user.model.UserToken;
import com.zbkj.crmeb.user.service.UserTokenService;
import com.zbkj.crmeb.wechat.service.WeChatService;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;


/**
 * <p>
 * 微信支付
 * </p>
 *
 * @author Mr.Zhang
 * @since 2020-04-10
 */
@Slf4j
@Data
@Service
public class WeChatPayServiceImpl implements WeChatPayService {
    private static final Logger logger = LoggerFactory.getLogger(WeChatPayServiceImpl.class);

    @Autowired
    private RestTemplateUtil restTemplateUtil;
    @Autowired
    private WeChatService weChatService;
    @Autowired
    private UserTokenService userTokenService;
    @Autowired
    private StoreOrderService storeOrderService;
    @Autowired
    private StoreOrderInfoService storeOrderInfoService;
    @Autowired
    private SystemConfigService systemConfigService;

    /**
     * 统一下单
     * @param payParamsVo PayParamsVo 支付参数
     * @author Mr.Zhang
     * @since 2020-06-22
     * @return PayResponseVo
     */
    @Override
    public CreateOrderResponseVo create(PayParamsVo payParamsVo){
        try {
            String signKey = null;
            UserToken userToken = null;
            CreateOrderRequestVo orderRequestVo = null;
            switch (payParamsVo.getFromType()){
                case Constants.PAY_TYPE_WE_CHAT_FROM_H5: //h5
                    orderRequestVo = setH5PayConfig();
                    signKey = systemConfigService.getValueByKey(Constants.CONFIG_KEY_PAY_WE_CHAT_APP_KEY + "_" + payParamsVo.getMerId());
                    signKey = null == signKey ? systemConfigService.getValueByKey(Constants.CONFIG_KEY_PAY_WE_CHAT_APP_KEY) : signKey;
                    break;
                case Constants.PAY_TYPE_WE_CHAT_FROM: //h5
                case Constants.PAY_TYPE_WE_CHAT_FROM_PUBLIC: //公众号
                    orderRequestVo = setPublicPayConfig();
                    signKey = systemConfigService.getValueByKey(Constants.CONFIG_KEY_PAY_WE_CHAT_APP_KEY + "_" + payParamsVo.getMerId());
                    signKey = null == signKey ? systemConfigService.getValueByKey(Constants.CONFIG_KEY_PAY_WE_CHAT_APP_KEY) : signKey;
                    userToken = userTokenService.getTokenByUserId(payParamsVo.getUserId(), Constants.THIRD_LOGIN_TOKEN_TYPE_PUBLIC);
                    orderRequestVo.setOpenid(userToken.getToken());
                    break;
                case Constants.PAY_TYPE_WE_CHAT_NATIVE: // 微信扫码支付
                	orderRequestVo = setPublicPayNativeConfig(payParamsVo.getMerId());
                	signKey = systemConfigService.getValueByKey(Constants.CONFIG_KEY_PAY_ROUTINE_APP_KEY + "_" + payParamsVo.getMerId());
                	signKey = null == signKey ? systemConfigService.getValueByKey(Constants.CONFIG_KEY_PAY_ROUTINE_APP_KEY) : signKey;
//                	userToken = userTokenService.getTokenByUserId(payParamsVo.getUserId(), Constants.THIRD_LOGIN_TOKEN_TYPE_PROGRAM);
//                	orderRequestVo.setOpenid(userToken.getToken());
                	break;
                case Constants.PAY_TYPE_WE_CHAT_FROM_PROGRAM: //小程序, 用户充值
                    orderRequestVo = setProgramPayConfig(payParamsVo.getMerId());
                    signKey = systemConfigService.getValueByKey(Constants.CONFIG_KEY_PAY_ROUTINE_APP_KEY + "_" + payParamsVo.getMerId());
                    signKey = null == signKey ? systemConfigService.getValueByKey(Constants.CONFIG_KEY_PAY_ROUTINE_APP_KEY) : signKey;
                    userToken = userTokenService.getTokenByUserId(payParamsVo.getUserId(), Constants.THIRD_LOGIN_TOKEN_TYPE_PROGRAM);
                    orderRequestVo.setOpenid(userToken.getToken());
                    break;
                default:
                    throw new CrmebException("系统不支持当前支付方式！");
            }
            orderRequestVo = createOrderWeChatData(orderRequestVo, payParamsVo, signKey);
            String request = XmlUtil.objectToXml(orderRequestVo);
            log.info("--------------- 微信下单原始参数: {} ---------------", request);
            // 海关清关原始参数保存
            storeOrderService.update(Wrappers.<StoreOrder>lambdaUpdate()
            		.set(StoreOrder :: getPayParam, request)
            		.eq(StoreOrder :: getOrderId, payParamsVo.getOrderNo())
            		);
            
            CreateOrderResponseVo createOrderResponseVo = response(orderRequestVo);
            return createOrderResponseVo;
        }catch (Exception e){
            logger.error("创建微信支付单失败, payParamsVo:{}",payParamsVo,e);
            throw new CrmebException(e.getMessage());
        }
    }

    @Override
    public CreateOrderResponseVo refund(String orderId) {
        // todo: 检查下是不是微信支付
        return null;
    }

    @Override
    public CreateOrderResponseVo closeOrder(String orderId) {
        return null;
    }

    /**
     * 处理下单之后返回的数据
     * @author Mr.Zhang
     * @since 2020-06-22
     */
    private CreateOrderResponseVo response(CreateOrderRequestVo orderRequestVo){
        try{
            String url = WeChatConstants.PAY_API_URL + WeChatConstants.PAY_API_URI;
            String request = XmlUtil.objectToXml(orderRequestVo);
            String xml = restTemplateUtil.postXml(url, request);
            HashMap<String, Object> map = XmlUtil.xmlToMap(xml);
            if(null == map){
                throw new CrmebException("微信下单失败！");
            }
            CreateOrderResponseVo responseVo = CrmebUtil.mapToObj(map, CreateOrderResponseVo.class);
            if(responseVo.getReturnCode().toUpperCase().equals("FAIL")){
                throw new CrmebException("微信下单失败1！" +  responseVo.getReturnMsg());
            }

            if(responseVo.getResultCode().toUpperCase().equals("FAIL")){
                throw new CrmebException("微信下单失败2！" + responseVo.getErrCodeDes());
            }

            responseVo.setExtra(orderRequestVo.getScene_info());
            return responseVo;
        }catch (Exception e){
            logger.error("微信下单失败! ",e);
            throw new CrmebException(e.getMessage());
        }
    }


    /**
     * 设置H5支付配置
     * @author Mr.Zhang
     * @since 2020-06-22
     */
    private CreateOrderRequestVo setH5PayConfig() {
        CreateOrderRequestVo requestVo = new CreateOrderRequestVo();
        String appId = systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_PAY_WE_CHAT_APP_ID);
        String mchId = systemConfigService.getValueByKey(Constants.CONFIG_KEY_PAY_WE_CHAT_MCH_ID);

        requestVo.setAppid(appId);
        requestVo.setMch_id(mchId);
        return requestVo;
    }

    /**
     * 设置H5支付配置
     * @author Mr.Zhang
     * @since 2020-06-22
     */
    private CreateOrderRequestVo setPublicPayConfig() {
        CreateOrderRequestVo requestVo = new CreateOrderRequestVo();
        String appId = systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_PAY_WE_CHAT_APP_ID);
        String mchId = systemConfigService.getValueByKey(Constants.CONFIG_KEY_PAY_WE_CHAT_MCH_ID);

        requestVo.setAppid(appId);
        requestVo.setMch_id(mchId);
        requestVo.setTrade_type(WeChatConstants.PAY_TYPE_JS);
//        getCreateOrderRequestVo().setOpenid(getOpenId(Constants.THIRD_LOGIN_TOKEN_TYPE_PUBLIC));
        return requestVo;
    }

    /**
     * 设置JS支付配置
     * @author Mr.Zhang
     * @since 2020-06-22
     */
    private CreateOrderRequestVo setPublicPayNativeConfig(Integer merId) {
        CreateOrderRequestVo requestVo = new CreateOrderRequestVo();
        String appId = systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_PAY_ROUTINE_APP_ID + "_" + merId);
        appId = null == appId ? systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_PAY_ROUTINE_APP_ID) : appId;
        String mchId = systemConfigService.getValueByKey(Constants.CONFIG_KEY_PAY_ROUTINE_MCH_ID + "_" + merId);
        mchId = null == mchId ? systemConfigService.getValueByKey(Constants.CONFIG_KEY_PAY_ROUTINE_MCH_ID) : mchId;

        requestVo.setAppid(appId);
        requestVo.setMch_id(mchId);
        requestVo.setTrade_type(WeChatConstants.PAY_TYPE_NATIVE);
//        getCreateOrderRequestVo().setOpenid(getOpenId(Constants.THIRD_LOGIN_TOKEN_TYPE_PROGRAM));
        return requestVo;
    }
    
    /**
     * 设置JS支付配置
     * @author Mr.Zhang
     * @since 2020-06-22
     */
    private CreateOrderRequestVo setProgramPayConfig(Integer merId) {
    	CreateOrderRequestVo requestVo = new CreateOrderRequestVo();
    	String appId = systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_PAY_ROUTINE_APP_ID + "_" + merId);
    	appId = null == appId ? systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_PAY_ROUTINE_APP_ID) : appId;
    	String mchId = systemConfigService.getValueByKey(Constants.CONFIG_KEY_PAY_ROUTINE_MCH_ID + "_" + merId);
    	mchId = null == mchId ? systemConfigService.getValueByKey(Constants.CONFIG_KEY_PAY_ROUTINE_MCH_ID) : mchId;
    	
    	requestVo.setAppid(appId);
    	requestVo.setMch_id(mchId);
    	requestVo.setTrade_type(WeChatConstants.PAY_TYPE_JS);
//        getCreateOrderRequestVo().setOpenid(getOpenId(Constants.THIRD_LOGIN_TOKEN_TYPE_PROGRAM));
    	return requestVo;
    }

    /**
     * 构建支付下单对象
     * @author Mr.Zhang
     * @since 2020-06-22
     */
    private CreateOrderRequestVo createOrderWeChatData(CreateOrderRequestVo createOrderRequestVo,PayParamsVo payParamsVo,String signKey){

        Integer price = payParamsVo.getPrice().multiply(BigDecimal.TEN).multiply(BigDecimal.TEN).intValue();
        //获取域名
        String domain = systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_SITE_URL);
        String apiDomain = systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_API_URL);

        String nonceStr = UUID.randomUUID().toString().replaceAll("-", "");

        String attach = JSONObject.toJSONString(payParamsVo.getAttach());
        CreateOrderH5SceneInfoVo createOrderH5SceneInfoVo = new CreateOrderH5SceneInfoVo(
                new CreateOrderH5SceneInfoDetailVo(
                        domain,
                        systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_SITE_NAME)
                )
        );
        String sceneInfo = JSONObject.toJSONString(createOrderH5SceneInfoVo);



        Map<String, String> map = new HashMap<String, String>();
        map.put("appid", createOrderRequestVo.getAppid());
        map.put("mch_id", createOrderRequestVo.getMch_id());
        map.put("nonce_str", nonceStr);
        map.put("body", payParamsVo.getTitle().replaceAll(" ", ""));
        map.put("out_trade_no", payParamsVo.getOrderNo());
        map.put("total_fee", String.valueOf(price));
        map.put("spbill_create_ip", payParamsVo.getClientIp());
        // TODO
        map.put("notify_url", apiDomain + WeChatConstants.PAY_NOTIFY_API_URI_WECHAT);
        map.put("trade_type", "JSAPI");
        map.put("attach",attach);
        map.put("scene_info",sceneInfo);
        map.put("openid", createOrderRequestVo.getOpenid());

        String preSignStr = ValidateUtils.createLinkStringHttp(map);
        preSignStr += "&key=" + signKey;
        String sign = MD5Util.MD5Encode(preSignStr).toUpperCase();

        //统一下单数据
        createOrderRequestVo.setNotify_url(apiDomain + WeChatConstants.PAY_NOTIFY_API_URI_WECHAT);
        createOrderRequestVo.setNonce_str(nonceStr);
        createOrderRequestVo.setBody(payParamsVo.getTitle().replaceAll(" ", ""));
        createOrderRequestVo.setOut_trade_no(payParamsVo.getOrderNo());

        //附加数据
        createOrderRequestVo.setAttach(attach);
        createOrderRequestVo.setTotal_fee(String.valueOf(price));
        createOrderRequestVo.setSpbill_create_ip(payParamsVo.getClientIp());

        createOrderRequestVo.setScene_info(sceneInfo);
//        createOrderRequestVo.setSign(CrmebUtil.getSign(CrmebUtil.objectToMap(createOrderRequestVo), signKey));
        createOrderRequestVo.setSign(sign);
        createOrderRequestVo.setFee_type(null);
        createOrderRequestVo.setReceipt(null);
        return createOrderRequestVo;
    }





    /**
     * 计算价格微信需要以分为单位，所以需要乘以100
     * @author Mr.Zhang
     * @since 2020-06-22
     * @return String
     */
//    private Integer getWeChatPrice(){
//        return getPayParamsVo().getPrice().multiply(BigDecimal.TEN).multiply(BigDecimal.TEN).intValue();
//    }

    /**
     * 构建场景信息对象
     * @author Mr.Zhang
     * @since 2020-06-22
     * @return PayCreateOrderSceneInfoVo
     */
//    private String getOpenId(int type) {
//        UserToken userToken = userTokenService.getTokenByUserId(getPayParamsVo().getUserId(), type);
//        return userToken.getToken();
//    }
}
